Function.RegisterNamespace("System.Script.ScriptLoadStrategy");

System.Script.ScriptLoadStrategy.Generic=function(){
    var _hasIndirectEval=false;
    var _needsReturnStatement=true;

    var _collapseRegex=/\{[^\{\}]*\}/g;
    var _identifierRegex=/(;?\s*)(var|function)(\s+)([^\s=(){}]+)(\s*=|\()/gm;

    new function Generic(){
        if(Object.Global()===eval.call(null,"this")){
            _hasIndirectEval=true;
            try{
                eval.call(null,"return {}");
            }catch(e){
                _needsReturnStatement=false;
            }
        }
    }

    // ILoadStrategy Members
    this.Import=function(path,callback){
        var script=System.IO.File.GetFile(System.IO.Path.GetFullPath(path));
        if(script==null)throw new Error(String.Format("System.Script.ScriptLoadStrategy.Generic.Import: There was an error loading '{0}'.\nError: File not found.",path));
        script=String.Format("{0}\n//@ sourceURL={1}",script,path.replace(/\s/g,'_'));
        var result=this.Load(script);
        if(callback)callback(path);
    };

    this.ImportJson=function(path,callback){
        var script=System.IO.File.GetFile(System.IO.Path.GetFullPath(path));
        if(script==null)throw new Error(String.Format("System.Script.ScriptLoadStrategy.Generic.ImportJson: There was an error loading '{0}'.\nError: File not found.",path));
        var result=this.Load(String.Format("{1}false||({0});\n//@ sourceURL={2}",script,_needsReturnStatement?"return ":"",path.replace(/\s/g,'_')));
        if(callback)callback(path,result);
    };

    this.Load=function(source){
        if(_hasIndirectEval){
            return eval.call(null,source);
        }
        return Function(promoteIdentifiers(source))();
    };

    // IStrategSpecification Members
    this.IsSatisfiedBy=function(candidate){
        return true;
    };

    // Private Methods
    function promoteIdentifiers(source){
        if(!source)return source;
        var identifiers=[];
        var collapsedSource=source;
        while(String.Contains(collapsedSource,'{')&&String.Contains(collapsedSource,'}')){
            collapsedSource=collapsedSource.replace(_collapseRegex,'');
        }
        collapsedSource.replace(_identifierRegex,addIdentifier);
        return [source].concat(identifiers).join('\n');
        function addIdentifier(fullMatch,leadingSpace,keyword,keywordSpace,identifier,trailingSpace){
            identifiers.push(String.Format("try{ {0}; Object.Global()[\"{0}\"]={0};}catch(e){ }",identifier));
            return fullMatch;
        }
    }
};

System.Script.ScriptLoadStrategy.Generic.Implement(System.Script.ScriptLoadStrategy.ILoadStrategy,'System.Script.ScriptLoadStrategy.Generic');
System.Script.ScriptLoadStrategy.Generic.Implement(System.Script.Strategy.IStrategySpecification,'System.Script.ScriptLoadStrategy.Generic');

System.Script.ScriptLoader.Strategies.Add(System.Script.ScriptLoadStrategy.Generic);